/**
 * @file control_commands.c
 * @brief 控制命令处理实现
 * @details 本文件实现了104协议中控制命令的处理功能，
 *          包括遥控命令的解析、构建、验证等操作。
 * 
 * @author zyb
 * @date 2025-10-16
 * @version 1.0
 * 
 * @note 控制命令格式严格按照IEC 60870-5-104协议规范
 * @warning 遥控命令包含选择和执行两个阶段
 * 
 * @see protocol_types.h
 * @see constants.h
 * @see error_codes.h
 */

#include "../include/control_commands.h"
#include "../../common/types/include/protocol_types.h"
#include "../../common/types/include/constants.h"
#include "../../common/error/include/error_codes.h"
#include "../../../common/logs/include/logger.h"
#include <string.h>

// 定义模块名称
#define LOG_MODULE_NAME "CONTROL_COMMANDS"

/* ==================== 遥控命令处理函数实现 ==================== */

/**
 * @brief 解析单点遥控命令
 * @details 从字节流中解析单点遥控命令，按照协议规范解析各个字段
 * 
 * @param buffer 输入缓冲区，不能为NULL
 * @param buffer_size 缓冲区大小
 * @param offset 偏移量
 * @param command 单点遥控命令结构输出，不能为NULL
 * @return 协议错误码
 */
protocol_error_t parse_single_command(const uint8_t* buffer, size_t buffer_size, size_t offset, single_command_t* command) {
    if (buffer == NULL || command == NULL) {
        LOG_ERROR(LOG_MODULE_NAME, "空指针参数错误");
        return PROTOCOL_ERROR_NULL_POINTER;
    }
    
    if (offset + 1 > buffer_size) {
        LOG_ERROR(LOG_MODULE_NAME, "缓冲区太小，无法读取单点遥控命令");
        return PROTOCOL_ERROR_BUFFER_TOO_SMALL;
    }
    
    uint8_t byte = buffer[offset];
    
    // 按照协议规范解析位域
    command->scs = byte & 0x01;           // Bit 1: 单点命令状态
    command->qu = (byte >> 2) & 0x1F;     // Bit 7-3: 限定词
    command->se = (byte >> 7) & 0x01;     // Bit 8: 选择/执行
    
    LOG_DEBUG(LOG_MODULE_NAME, "单点遥控命令解析: 0x%02X -> SCS=%d, QU=%d, S/E=%d", 
              byte, command->scs, command->qu, command->se);
    
    return PROTOCOL_SUCCESS;
}

/**
 * @brief 构建单点遥控命令
 * @details 将单点遥控命令结构转换为字节流，按照协议规范构建各个位域
 * 
 * @param command 单点遥控命令结构，不能为NULL
 * @param buffer 输出缓冲区，不能为NULL
 * @param offset 偏移量
 * @return 协议错误码
 */
protocol_error_t build_single_command(const single_command_t* command, uint8_t* buffer, size_t offset) {
    if (command == NULL || buffer == NULL) {
        LOG_ERROR(LOG_MODULE_NAME, "空指针参数错误");
        return PROTOCOL_ERROR_NULL_POINTER;
    }
    
    uint8_t byte = 0;
    
    // 按照协议规范构建位域
    byte |= (command->scs & 0x01);                    // Bit 1: 单点命令状态
    byte |= ((command->qu & 0x1F) << 2);              // Bit 7-3: 限定词
    byte |= ((command->se & 0x01) << 7);              // Bit 8: 选择/执行
    
    buffer[offset] = byte;
    
    LOG_DEBUG(LOG_MODULE_NAME, "单点遥控命令构建: SCS=%d, QU=%d, S/E=%d -> 0x%02X", 
              command->scs, command->qu, command->se, byte);
    
    return PROTOCOL_SUCCESS;
}

/**
 * @brief 解析双点遥控命令
 * @details 从字节流中解析双点遥控命令，按照协议规范解析各个字段
 * 
 * @param buffer 输入缓冲区，不能为NULL
 * @param buffer_size 缓冲区大小
 * @param offset 偏移量
 * @param command 双点遥控命令结构输出，不能为NULL
 * @return 协议错误码
 */
protocol_error_t parse_double_command(const uint8_t* buffer, size_t buffer_size, size_t offset, double_command_t* command) {
    if (buffer == NULL || command == NULL) {
        LOG_ERROR(LOG_MODULE_NAME, "空指针参数错误");
        return PROTOCOL_ERROR_NULL_POINTER;
    }
    
    if (offset + 1 > buffer_size) {
        LOG_ERROR(LOG_MODULE_NAME, "缓冲区太小，无法读取双点遥控命令");
        return PROTOCOL_ERROR_BUFFER_TOO_SMALL;
    }
    
    uint8_t byte = buffer[offset];
    
    // 按照协议规范解析位域
    command->dcs = byte & 0x03;           // Bit 2-1: 双点命令状态
    command->qu = (byte >> 2) & 0x1F;     // Bit 7-3: 限定词
    command->se = (byte >> 7) & 0x01;     // Bit 8: 选择/执行
    
    LOG_DEBUG(LOG_MODULE_NAME, "双点遥控命令解析: 0x%02X -> DCS=%d, QU=%d, S/E=%d", 
              byte, command->dcs, command->qu, command->se);
    
    return PROTOCOL_SUCCESS;
}

/**
 * @brief 构建双点遥控命令
 * @details 将双点遥控命令结构转换为字节流，按照协议规范构建各个位域
 * 
 * @param command 双点遥控命令结构，不能为NULL
 * @param buffer 输出缓冲区，不能为NULL
 * @param offset 偏移量
 * @return 协议错误码
 */
protocol_error_t build_double_command(const double_command_t* command, uint8_t* buffer, size_t offset) {
    if (command == NULL || buffer == NULL) {
        LOG_ERROR(LOG_MODULE_NAME, "空指针参数错误");
        return PROTOCOL_ERROR_NULL_POINTER;
    }
    
    uint8_t byte = 0;
    
    // 按照协议规范构建位域
    byte |= (command->dcs & 0x03);                    // Bit 2-1: 双点命令状态
    byte |= ((command->qu & 0x1F) << 2);              // Bit 7-3: 限定词
    byte |= ((command->se & 0x01) << 7);              // Bit 8: 选择/执行
    
    buffer[offset] = byte;
    
    LOG_DEBUG(LOG_MODULE_NAME, "双点遥控命令构建: DCS=%d, QU=%d, S/E=%d -> 0x%02X", 
              command->dcs, command->qu, command->se, byte);
    
    return PROTOCOL_SUCCESS;
}

/* ==================== 遥控命令验证函数实现 ==================== */

/**
 * @brief 验证单点遥控命令
 * @details 验证单点遥控命令的各个位域是否有效
 * 
 * @param command 单点遥控命令结构，不能为NULL
 * @return 协议错误码
 */
protocol_error_t validate_single_command(const single_command_t* command) {
    if (command == NULL) {
        LOG_ERROR(LOG_MODULE_NAME, "空指针参数错误");
        return PROTOCOL_ERROR_NULL_POINTER;
    }
    
    // 验证SCS值范围 (0-1)
    // 注意: scs是1位位域，范围已被类型限制为0-1，无需检查
    // if ((unsigned)command->scs > 1) { ... } // 已移除，总是为假
    
    // 验证QU值范围 (0-31)
    // 注意: qu是5位位域，范围已被类型限制为0-31，无需检查
    // if ((unsigned)command->qu > 31) { ... } // 已移除，总是为假
    
    // 验证S/E位域值范围
    // 注意: se是1位位域，范围已被类型限制为0-1，无需检查
    // if ((unsigned)command->se > 1) { ... } // 已移除，总是为假
    
    return PROTOCOL_SUCCESS;
}

/**
 * @brief 验证双点遥控命令
 * @details 验证双点遥控命令的各个位域是否有效
 * 
 * @param command 双点遥控命令结构，不能为NULL
 * @return 协议错误码
 */
protocol_error_t validate_double_command(const double_command_t* command) {
    if (command == NULL) {
        LOG_ERROR(LOG_MODULE_NAME, "空指针参数错误");
        return PROTOCOL_ERROR_NULL_POINTER;
    }
    
    // 验证DCS值范围 (0-3)
    // 注意: dcs是2位位域，范围已被类型限制为0-3，无需检查
    // if ((unsigned)command->dcs > 3) { ... } // 已移除，总是为假
    
    // 验证QU值范围 (0-31)
    // 注意: qu是5位位域，范围已被类型限制为0-31，无需检查
    // if ((unsigned)command->qu > 31) { ... } // 已移除，总是为假
    
    // 验证S/E位域值范围
    // 注意: se是1位位域，范围已被类型限制为0-1，无需检查
    // if ((unsigned)command->se > 1) { ... } // 已移除，总是为假
    
    return PROTOCOL_SUCCESS;
}

/* ==================== 遥控命令状态处理函数实现 ==================== */

/**
 * @brief 获取单点遥控命令状态描述
 * @details 根据单点遥控命令的SCS值获取对应的状态描述
 * 
 * @param scs 单点命令状态值
 * @return 状态描述字符串
 */
const char* get_single_command_status_desc(uint8_t scs) {
    switch (scs) {
        case 0:
            return "OFF (开)";
        case 1:
            return "ON (合)";
        default:
            return "未知状态";
    }
}

/**
 * @brief 获取双点遥控命令状态描述
 * @details 根据双点遥控命令的DCS值获取对应的状态描述
 * 
 * @param dcs 双点命令状态值
 * @return 状态描述字符串
 */
const char* get_double_command_status_desc(uint8_t dcs) {
    switch (dcs) {
        case 0:
            return "不允许";
        case 1:
            return "OFF (开)";
        case 2:
            return "ON (合)";
        case 3:
            return "不允许";
        default:
            return "未知状态";
    }
}

/**
 * @brief 获取遥控输出方式描述
 * @details 根据QU值获取对应的遥控输出方式描述
 * 
 * @param qu 限定词值
 * @return 输出方式描述字符串
 */
const char* get_qualifier_desc(uint8_t qu) {
    switch (qu) {
        case 0:
            return "无定义";
        case 1:
            return "短脉冲持续时间(断路器)";
        case 2:
            return "长脉冲持续时间";
        case 3:
            return "持续输出";
        case 4:
        case 5:
        case 6:
        case 7:
        case 8:
            return "配套标准保留";
        case 9:
        case 10:
        case 11:
        case 12:
        case 13:
        case 14:
        case 15:
            return "其他预先定义功能保留";
        case 16:
        case 17:
        case 18:
        case 19:
        case 20:
        case 21:
        case 22:
        case 23:
        case 24:
        case 25:
        case 26:
        case 27:
        case 28:
        case 29:
        case 30:
        case 31:
            return "特殊用途保留";
        default:
            return "未知限定词";
    }
}

/**
 * @brief 获取选择/执行状态描述
 * @details 根据S/E位获取对应的选择/执行状态描述
 * 
 * @param se 选择/执行位值
 * @return 状态描述字符串
 */
const char* get_select_execute_desc(uint8_t se) {
    switch (se) {
        case 0:
            return "执行";
        case 1:
            return "选择";
        default:
            return "未知状态";
    }
}

/* ==================== 遥控命令流程处理函数实现 ==================== */

/**
 * @brief 检查遥控命令是否有效
 * @details 检查遥控命令的各个位域是否有效，包括状态值和限定词
 * 
 * @param command_type 命令类型 (单点或双点)
 * @param status 命令状态值
 * @param qu 限定词值
 * @return 1表示有效，0表示无效
 */
int is_valid_control_command(uint8_t command_type, uint8_t status, uint8_t qu) {
    // 验证限定词范围
    if (qu > 31) {
        return 0;
    }
    
    if (command_type == 1) {  // 单点命令
        return (status <= 1);
    } else if (command_type == 2) {  // 双点命令
        return (status <= 3);
    }
    
    return 0;
}

/**
 * @brief 检查遥控命令是否为选择阶段
 * @details 检查遥控命令是否为选择阶段 (S/E=1)
 * 
 * @param se 选择/执行位值
 * @return 1表示是选择阶段，0表示是执行阶段
 */
int is_select_phase(uint8_t se) {
    return (se == 1);
}

/**
 * @brief 检查遥控命令是否为执行阶段
 * @details 检查遥控命令是否为执行阶段 (S/E=0)
 * 
 * @param se 选择/执行位值
 * @return 1表示是执行阶段，0表示是选择阶段
 */
int is_execute_phase(uint8_t se) {
    return (se == 0);
}
